# SKIP（Social Knowledge & Innovation Platform）
# Copyright (C) 2008  TIS Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

class OccasionController < ApplicationController
  helper 'occasion_board_entries'
  before_filter :setup_layout

  before_filter :check_owned,
                :only => [ :manage, :managers, :permit,
                           :update, :destroy, :toggle_owned, :permit_participation ]

  verify :method => :post,
         :only => [ :join, :destroy, :leave, :update, :change_participation, :ado_set_favorite ],
         :redirect_to => { :action => :show }

  # tab_menu
  def show
    @admin_users = @occasion.participation_users :order => "occasion_participations.updated_on DESC",
                                              :owned => true,
                                              :waiting => false
    @users = @occasion.participation_users :limit => 20,
                                        :order => "occasion_participations.updated_on DESC",
                                        :owned => false,
                                        :waiting => false
# TODO by kyuumin 無制限にする方法が分からなかったので、そのまま。第一引数を変える？
    @recent_messages = OccasionBoardEntry.find_visible(5, occasion_login_user_symbols, @occasion.symbol)
  end

  # tab_menu
  def users
    @condition = UserSearchCondition.create_by_params params

    conditions = ["occasion_participations.occasion_id = ? and occasion_participations.waiting = ?", @occasion.id, false]
    conditions[0] << " and occasion_participations.owned = false" unless @condition.include_manager?

    order_by = @condition.value_of_order_by

    per_page = 10
    case @condition.output_type
    when "normal"
      per_page = 5
    when "list"
      per_page = 20
    when "csv"
      csv_text = User.find_as_csv(:all,
                                  :conditions => conditions,
                                  :order => order_by,
                                  :include => [:user_access, :occasion_participations])
      send_data csv_text, :filename => 'users.csv', :type => 'application/x-csv', :disposition => 'attachment'
      return nil
    end

    @pages, @users = paginate(:user,
                              :per_page => per_page,
                              :conditions => conditions,
                              :order_by => order_by,
                              :include => [:user_access, :pictures, :occasion_participations, :user_uids])
    unless @users && @users.size > 0
      flash.now[:notice] = '該当するユーザは存在しませんでした。'
    end
  end

  # tab_menu
  def bbs
    order = "last_updated DESC,occasion_board_entries.id DESC"
    options = { :symbol => @occasion.symbol }

    # 左側
    setup_bbs_left_box options

    # 右側
    if entry_id = params[:entry_id]
      options[:id] = entry_id
      find_params = OccasionBoardEntry.make_conditions(occasion_login_user_symbols, options)

      @entry = OccasionBoardEntry.find(:first,
                               :order => order,
                               :conditions => find_params[:conditions],
                               :include => find_params[:include] | [ :user, :occasion_board_entry_comment, :state ])

      if @entry
        login_user_id = session[:user_id]
        @entry.accessed(login_user_id)
        @prev_entry, @next_entry = @entry.get_around_entry(occasion_login_user_symbols)
        @editable = @entry.editable?(occasion_login_user_symbols, login_user_id);
# TODO by kyuumin トラックバックを使う場合はここを有効にする
#        @tb_entries = @entry.trackback_entries(login_user_id, occasion_login_user_symbols)
        @title += " - " + @entry.title

        @entry_accesses =  OccasionEntryAccess.find_by_entry_id @entry.id
        @total_count = @entry.state.access_count
# TODO by kyuumin ブックマークを使う場合はここを有効にする
#        bookmark = Bookmark.find(:first, :conditions =>["url = ?", "/page/"+@entry.id.to_s])
#        @bookmark_comments_count = bookmark ? bookmark.bookmark_comments_count : 0
      end
    else
      options[:category] = params[:category]
      options[:keyword] = params[:keyword]

      params[:sort_type] ||= "date"
      if params[:sort_type] == "access"
        order = "board_entry_points.access_count DESC"
      end

      find_params = OccasionBoardEntry.make_conditions(occasion_login_user_symbols, options)

      if @user = params[:user]
        find_params[:conditions][0] << " and occasion_board_entries.user_id = ?"
        find_params[:conditions] << @user
      end

      @pages, @entries = paginate(:occasion_board_entries,
                                  :per_page => 20,
                                  :order => order,
                                  :conditions => find_params[:conditions],
                                  :include => find_params[:include] | [ :user, :occasion_board_entry_comment, :state ])
    end

  end

  # tab_menu
  def search
    redirect_to(:controller => 'occasion_items',
                :action => '',
                :entry_type => OccasionBoardEntry::OCCASION_BBS,
                :category => @occasion.category,
                :symbol => @occasion.symbol)
  end

  # tab_menu
  def new
    redirect_to(:controller => 'occasion_edit',
                :action => '',
                :entry_type => OccasionBoardEntry::OCCASION_BBS,
                :symbol => @occasion.symbol,
                :publication_type => "private")
  end

  # tab_menu
  def new_participation
    render :layout => 'dialog'
  end

  # tab_menu
  def manage
    @menu = params[:menu] || "manage_info"

    case @menu
    when "manage_info"
      #
    when "manage_participations"
      @pages, @participations = paginate_participations(@occasion, false)
    when "manage_permit"
      unless @occasion.protected?
        flash[:warning] = "参加に承認は不要です"
        redirect_to :action => :manage
        return
      end
      @pages, @participations = paginate_participations(@occasion, true)
    end
    render :partial => @menu, :layout => "layout"
  end

  # tab_menu
  def share_file
    params.store(:owner_name, @occasion.name)
    params.store(:visitor_is_uploader, @participation)
    text = render_component_as_string :controller => 'share_file', :action => 'list', :id => @occasion.symbol, :params => params
    render :text => text, :layout => 'layout'
  end

  # post_action
  # 参加申込み
  def join
    if @participation
      flash[:notice] = '既に参加しています。'
    else
      participation = OccasionParticipation.new(:user_id => session[:user_id], :occasion_id => @occasion.id)
      participation.waiting = true if @occasion.protected?

      if participation.save
        if participation.waiting?
          flash[:notice] = '参加申し込みをしました。承認されるのをお待ちください。'
        else
          login_user_occasions << @occasion.symbol
          flash[:notice] = 'お祝いイベントに参加しました。'
        end

        message = params[:board_entry][:contents]

        #お祝いイベントのownerのシンボル(複数と取ってきて、publication_symbolsに入れる)
        owner_symbols = @occasion.get_owners.map { |user| user.symbol }
        entry_params = { }
        entry_params[:title] = "参加申し込みをしました！"
        entry_params[:message] = render_to_string(:partial => 'occasion_entries_template/occasion_join',
                                                  :locals => { :user_name => session[:user_name],
                                                               :message => message })
        entry_params[:occasion_tags] = "参加申し込み"
        entry_params[:occasion_tags] << ",#{OccasionTag::NOTICE_TAG}" if @occasion.protected?
        entry_params[:user_symbol] = session[:user_symbol]
        entry_params[:user_id] = session[:user_id]
        entry_params[:entry_type] = OccasionBoardEntry::OCCASION_BBS
        entry_params[:owner_symbol] = @occasion.symbol
        entry_params[:publication_type] = 'protected'
        entry_params[:publication_symbols] = owner_symbols + [session[:user_symbol]]

        board_entry =  OccasionBoardEntry.create_entry(entry_params)
      end
    end
    redirect_to :action => 'show'
  end

  # post_action
  # 退会
  def leave
    if @participation
      if @participation.destroy
        login_user_occasions.delete(@occasion.symbol)
        flash[:notice] = '退会しました。'
      end
    else
      flash[:notice] = 'そのお祝いイベントには参加していません。'
    end
    redirect_to :action => 'show'
  end

  # post_action ... では無いので後に修正が必要
  # 管理者変更
  def toggle_owned
    occasion_participation = OccasionParticipation.find(params[:participation_id])
    occasion_participation.owned = !occasion_participation.owned?

    if occasion_participation.save
      flash[:notice] = '変更しました。'
    else
      flash[:warning] = '権限変更に失敗しました。'
    end
    redirect_to :action => 'manage', :menu => 'manage_participations'
  end

  # 管理者による強制退会処理
  def forced_leave_user
    unless occasion_participation = OccasionParticipation.find_by_id(params[:participation_id])
      flash[:warning] = "そのユーザは既に退会しています。"
      redirect_to :action => 'manage', :menu => 'manage_participations'
      return false
    end

    user = occasion_participation.user
    occasion_participation.destroy

    # BBSにuid直接指定[連絡]で新規投稿(自動で投稿されて保存される)
    entry_params = { }
    entry_params[:title] ="【#{@occasion.name}】退会処理"
    entry_params[:message] = "[#{@occasion.symbol}>]から#{user.name}さんの退会処理を実行しました"
    entry_params[:occasion_tags] = "#{OccasionTag::NOTICE_TAG}"
    entry_params[:user_symbol] = session[:user_symbol]
    entry_params[:user_id] = session[:user_id]
    entry_params[:entry_type] = OccasionBoardEntry::OCCASION_BBS
    entry_params[:owner_symbol] = @occasion.symbol
    entry_params[:publication_type] = 'protected'
    entry_params[:publication_symbols] = [session[:user_symbol]]
    entry_params[:publication_symbols] << user.symbol
    entry = OccasionBoardEntry.create_entry(entry_params)

    flash[:notice] = "退会者向けに掲示板にメッセージを作成しました。内容は必要に応じて変更してください"
    redirect_to :action => 'bbs', :entry_id => entry.id
  end

  # post_action
  # 参加の許可か棄却
  def change_participation
    unless @occasion.protected?
      flash[:warning] = "参加に承認は不要です"
      redirect_to :action => :show
    end

    type_name = params[:submit_type] == 'permit' ? "許可" : "棄却"

    if states = params[:participation_state]
      states.each do |participation_id, state|
        if eval(state)
          participation = OccasionParticipation.find(participation_id)
          result = nil
          if params[:submit_type] == 'permit'
            participation.waiting = false
            result = participation.save
          else
            result = participation.destroy
          end

          flash[:notice] = type_name + ( result ? 'しました。' : 'に失敗しました。')
        end
      end
    end
    redirect_to :action => 'manage', :menu => 'manage_permit'
  end

  # post_action
  # 更新
  def update
    if @occasion.update_attributes(params[:occasion])
      flash.now[:notice] = 'お祝いイベント情報は正しく更新されました。'
    end
    manage
  end

  # post_action
  # 削除
  def destroy
    if @occasion.occasion_participations.size > 1
      flash[:warning] = '自分以外のユーザがまだ存在しています。削除できません。'
    elsif @occasion.destroy
      flash[:notice] = 'お祝いイベントは削除されました。'
      redirect_to :controller => 'occasions'
      return
    else
      flash[:notice] = 'お祝いイベントの削除に失敗しました。'
    end
    redirect_to :action => 'show'
  end

  # ajax action
  # お気に入りのステータスを設定する
  def ado_set_favorite
    par_id = params[:occasion_participation_id]
    favorite_flag = params[:favorite_flag]
    participation = @occasion.occasion_participations.find(par_id)
    participation.update_attribute(:favorite, favorite_flag)
    render :partial => "occasions/favorite", :locals => { :oid => @occasion.oid, :participation => participation, :update_elem_id => params[:update_elem_id]}
  end

  # 参加者追加(管理者のみ)
  def append_user
    # 参加制約は追加しない。制約は制約管理で。
    symbol_type, symbol_id = Symbol.split_symbol params[:symbol]
    case symbol_type
    when 'uid'
      user = User.find_by_uid(symbol_id)
      if @occasion.occasion_participations.find_by_user_id(user.id)
        flash[:notice] = "#{user.name}さんは既に参加済み/参加申請済みです。"
      else
        @occasion.occasion_participations.build(:user_id => user.id, :owned => false)
        @occasion.save
        flash[:notice] = "#{user.name}さんを参加者に追加し、連絡の掲示板を作成しました。"
      end
    when 'oid'
      occasion = Occasion.find_by_oid(symbol_id, :include => :occasion_participations)
      occasion.occasion_participations.each do |participation|
        unless @occasion.occasion_participations.find_by_user_id(participation.user_id)
          @occasion.occasion_participations.build(:user_id => participation.user_id, :owned => false)
        end
      end
      @occasion.save
      flash[:notice] = "#{occasion.name}のメンバーを参加者に追加し、連絡の掲示板を作成しました。"
    else
      flash[:warning] = "ユーザ／グループの指定方法が間違っています"
    end

    # BBSにsymbol直接指定[連絡]で新規投稿(自動で投稿されて保存される)
    @occasion.create_entry_invite_occasion(session[:user_id],
                                     session[:user_symbol],
                                     [params[:symbol], session[:user_symbol]])

    redirect_to :action => 'manage', :menu => 'manage_participations'
  end


private
  def setup_layout
    if @occasion = Occasion.find_by_oid(params[:oid])
      flash[:warning] ||= nil
    else
      flash[:warning] = "指定のお祝いイベントは存在していません"
      redirect_to :controller => 'occasions', :action => 'index'
      return false
    end

    @participation = @occasion.occasion_participations.find_by_user_id(session[:user_id])

    @main_menu = 'お祝いイベント'
    @title = @occasion.name

    @tab_menu_source = []
    @tab_menu_source << ['サマリ', 'show']
    @tab_menu_source << ['参加者一覧', 'users']
    @tab_menu_source << ['掲示板', 'bbs']
    @tab_menu_source << ['新規投稿', 'new'] if participating?
    @tab_menu_source << ['プレゼントを探す', 'search'] if participating?
#    @tab_menu_source << ['共有ファイル', 'share_file']
    @tab_menu_source << ['管理', 'manage'] if participating? and @participation.owned?

    @tab_menu_option = { :oid => @occasion.oid }
  end

  def participating?
    @participation and @participation.waiting? != true
  end

  def check_owned
    unless @participation and @participation.owned?
      flash[:warning] = 'その操作は管理者権限が必要です。'
      redirect_to :action => 'show'
      return false
    end
  end


  def paginate_participations occasion, waiting
    return paginate(:occasion_participations,
                    :per_page => 20,
                    :conditions => ["occasion_participations.occasion_id = ? and occasion_participations.waiting = ?", occasion.id, waiting],
                    :include => :user)
  end

  def setup_bbs_left_box options
    find_params = OccasionBoardEntry.make_conditions(occasion_login_user_symbols, options)
    # 最近の投稿
    @recent_entries = OccasionBoardEntry.find(:all,
                                      :limit => 5,
                                      :conditions => find_params[:conditions],
                                      :include => find_params[:include],
                                      :order => "last_updated DESC,occasion_board_entries.id DESC")
    # カテゴリ
    @categories = OccasionBoardEntry.get_category_words(find_params)

    # 人毎のアーカイブ
    select_state = "count(distinct occasion_board_entries.id) as count, users.name as user_name, users.id as user_id"
    joins_state = "LEFT OUTER JOIN occasion_entry_publications ON occasion_entry_publications.occasion_board_entry_id = occasion_board_entries.id"
    joins_state << " LEFT OUTER JOIN users ON users.id = occasion_board_entries.user_id"
    find_params[:conditions].first << " and category not like '%[参加申し込み]%'"
    @user_archives = OccasionBoardEntry.find(:all,
                                     :select => select_state,
                                     :conditions=> find_params[:conditions],
                                     :group => "user_id",
                                     :order => "count desc",
                                     :joins => joins_state)
  end

end
